package com.vesper.mysdk;


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;

import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.core.graphics.BlendModeCompat;
import androidx.core.graphics.PaintCompat;

import java.util.ArrayList;
import java.util.List;

public class WordParticleView extends View {

    private char[] text = "😁".toCharArray();
    private final DisplayMetrics mDM;
    Paint.FontMetrics fm = new Paint.FontMetrics();
    boolean shouldUpdateTextPath = true;

    private TextPaint mPaint;

    {
        mDM = getResources().getDisplayMetrics();
        initPaint();
    }

    private void initPaint() {
        //否则提供给外部纹理绘制
        mPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setAntiAlias(false);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setTextSize(dp2px(150));
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        PaintCompat.setBlendMode(mPaint, BlendModeCompat.LIGHTEN);
    }

    public WordParticleView(Context context) {
        this(context, null);
    }

    public WordParticleView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WordParticleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = View.MeasureSpec.getSize(widthMeasureSpec);


        if (widthMode != MeasureSpec.EXACTLY) {
            widthSize = mDM.widthPixels;
        }

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        if (heightMode != MeasureSpec.EXACTLY) {
            heightSize = widthSize;
        }
        setMeasuredDimension(widthSize, heightSize);
    }

    public void setText(String text) {
        if (text == null) return;
        shouldUpdateTextPath = true;
        this.text = text.toCharArray();
    }

    //记录点位，保存重合点位
    List<Particle> points = new ArrayList<>();
    Path textPath = new Path(); // 文本路径
    //文本区域，这里是指文字路径区域，并不是文字大小区域
    Region textPathRegion = new Region();
    //这里才是文本区域
    Region mainRegion = new Region();
    //文本区域边界
    RectF textRect = new RectF();
    //分片区域边界
    Rect measureRect = new Rect();

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        shouldUpdateTextPath = true;
    }


    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (text == null) return;
        int saveRecord = canvas.save();
        canvas.translate(getWidth() / 2f, getHeight() / 2f);
        float measureTextWidth = mPaint.measureText(text, 0, text.length);
        float baseline = getTextPaintBaseline(mPaint);
        final int step = 3;  //步长

        if (shouldUpdateTextPath) {
            textPath.reset();
            mPaint.getTextPath(text, 0, text.length, -(measureTextWidth / 2f), baseline, textPath);
            shouldUpdateTextPath = false;

            //染色区域设置
            textPath.computeBounds(textRect, true);
            mainRegion.set((int) textRect.left, (int) textRect.top, (int) textRect.right, (int) textRect.bottom);
            textPathRegion.setPath(textPath, mainRegion);

            float textRectWidth = textRect.width();
            float textRectHeight = textRect.height();

            int index = 0;

            for (int i = 0; i < textRectHeight; i += step) {
                for (int j = 0; j < textRectWidth; j += step) {
                    int row = (int) (-textRectHeight / 2 + i * step);
                    int col = (int) (-textRectWidth / 2 + j * step);
                    measureRect.set(col, row, col + step, row + step);
                    if (!textPathRegion.contains(measureRect.centerX(), measureRect.centerY())) {
                        continue;
                    }

                    Particle p = points.size() > index ? points.get(index) : null;
                    index++;
                    if (p == null) {
                        p = new Particle();
                        points.add(p);
                    }
                    p.x = measureRect.centerX();
                    p.y = measureRect.centerY();

                    double random = Math.random();
                    hsl[0] = (float) (random * 360);
                    hsl[1] = 0.5f;
                    hsl[2] = 0.5f;  //最亮
                    p.color = HSLToColor(hsl);

                    int randomInt = 1 + (int) (Math.random() * 100);
                    float t = (float) ((randomInt % 2 == 0 ? -1f : 1f) * Math.random());
                    p.radius = (float) (step * random);
                    p.range = step * 5;
                    p.t = t;
                }
            }
            while (points.size() > index + 1) {
                points.remove(points.size() - 1);
            }

        }

        float textSize = mPaint.getTextSize();
        for (int i = 0; i < points.size(); i += 2) {
            Particle point = points.get(i);
            mPaint.setColor(point.color);
            canvas.drawCircle(point.x,point.y,point.radius,mPaint);
            point.update();
        }
        mPaint.setTextSize(textSize);

        canvas.restoreToCount(saveRecord);

        postInvalidateDelayed(0);
    }

    public float getTextPaintBaseline(Paint p) {
        p.getFontMetrics(fm);
        Paint.FontMetrics fontMetrics = fm;
        return (fontMetrics.descent - fontMetrics.ascent) / 2 - fontMetrics.descent;
    }

    public float dp2px(float dp) {
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, getResources().getDisplayMetrics());
    }

    public static int argb(float alpha, float red, float green, float blue) {
        return ((int) (alpha * 255.0f + 0.5f) << 24) |
                ((int) (red * 255.0f + 0.5f) << 16) |
                ((int) (green * 255.0f + 0.5f) << 8) |
                (int) (blue * 255.0f + 0.5f);
    }

    float[] hsl = new float[3];

    @ColorInt
    public static int HSLToColor(@NonNull float[] hsl) {
        final float h = hsl[0];
        final float s = hsl[1];
        final float l = hsl[2];

        final float c = (1f - Math.abs(2 * l - 1f)) * s;
        final float m = l - 0.5f * c;
        final float x = c * (1f - Math.abs((h / 60f % 2f) - 1f));

        final int hueSegment = (int) h / 60;

        int r = 0, g = 0, b = 0;

        switch (hueSegment) {
            case 0:
                r = Math.round(255 * (c + m));
                g = Math.round(255 * (x + m));
                b = Math.round(255 * m);
                break;
            case 1:
                r = Math.round(255 * (x + m));
                g = Math.round(255 * (c + m));
                b = Math.round(255 * m);
                break;
            case 2:
                r = Math.round(255 * m);
                g = Math.round(255 * (c + m));
                b = Math.round(255 * (x + m));
                break;
            case 3:
                r = Math.round(255 * m);
                g = Math.round(255 * (x + m));
                b = Math.round(255 * (c + m));
                break;
            case 4:
                r = Math.round(255 * (x + m));
                g = Math.round(255 * m);
                b = Math.round(255 * (c + m));
                break;
            case 5:
            case 6:
                r = Math.round(255 * (c + m));
                g = Math.round(255 * m);
                b = Math.round(255 * (x + m));
                break;
        }

        r = constrain(r, 0, 255);
        g = constrain(g, 0, 255);
        b = constrain(b, 0, 255);

        return Color.rgb(r, g, b);
    }

    private static int constrain(int amount, int low, int high) {
        return amount < low ? low : Math.min(amount, high);
    }

    static class Particle extends PointF {

        float t;
        int color;
        float radius;
        float range;

        public void update() {
            radius = radius + t;
            if (radius >= range || radius <= 0) {
                t = -t;
            }
            if (radius < 0) {
                radius = 0;
            }
            if(radius > range){
                radius = range;
            }
        }
    }
}
